package com.wh.wisdomsite.xbox.core.security.impl;

import com.wh.wisdomsite.xbox.common.Constants;
import com.wh.wisdomsite.xbox.common.ServiceMethodDefinition;
import com.wh.wisdomsite.xbox.common.XboxContext;
import com.wh.wisdomsite.xbox.common.annotation.DeviceType;
import com.wh.wisdomsite.xbox.common.annotation.HttpAction;
import com.wh.wisdomsite.xbox.common.annotation.MessageFormat;
import com.wh.wisdomsite.xbox.common.session.Session;
import com.wh.wisdomsite.xbox.core.security.AppSecretManager;
import com.wh.wisdomsite.xbox.core.impl.DefaultXboxRequestContext;
import com.wh.wisdomsite.xbox.common.error.SubErrorType;
import com.wh.wisdomsite.xbox.common.error.SubErrors;
import com.wh.wisdomsite.xbox.common.error.SubError;
import com.wh.wisdomsite.xbox.common.error.MainError;
import com.wh.wisdomsite.xbox.common.error.MainErrors;
import com.wh.wisdomsite.xbox.common.error.MainErrorType;
import com.wh.wisdomsite.xbox.core.security.SecurityManager;
import com.wh.wisdomsite.xbox.core.security.InvokeTimesController;
import com.wh.wisdomsite.xbox.core.security.ServiceAccessController;
import com.wh.wisdomsite.xbox.common.session.SessionManager;
import com.wh.wisdomsite.xbox.core.model.SignRule;
import com.wh.wisdomsite.xbox.utils.StringUtils;
import com.wh.wisdomsite.xbox.utils.encrypt.hmacSHA1.HmacSHA1;
import com.wh.wisdomsite.xbox.utils.json.JsonUtil_Google;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.validation.FieldError;
import org.springframework.validation.ObjectError;
import java.util.*;
import com.wh.wisdomsite.xbox.utils.Base64;


/**
 * 控制方法是否允许被访问接口实现类
 * @Package com.wh.wisdomsite.xbox.core.security.impl
 * @author 谢泽鹏
 * @date 2014年10月8日 下午4:02:14
 * @Copyright 个人版权所有
 * @Company 贵州万华科技有限公司Copyright (c) 2014
 * @version V1.0
 */
public class XboxSecurityManager implements SecurityManager {

    private static final Log logger = LogFactory.getLog(XboxSecurityManager.class);

    private ServiceAccessController serviceAccessController;

    private InvokeTimesController invokeTimesController;

    private AppSecretManager appSecretManager;

    private SessionManager sessionManager;

    private static final Map<String, SubErrorType> INVALIDE_CONSTRAINT_SUBERROR_MAPPINGS = new LinkedHashMap<String, SubErrorType>();


    static {
        //业务参数不匹配
        INVALIDE_CONSTRAINT_SUBERROR_MAPPINGS.put("typeMismatch", SubErrorType.ISV_PARAMETERS_MISMATCH);
        //服务业务参数丢失
        INVALIDE_CONSTRAINT_SUBERROR_MAPPINGS.put("NotNull", SubErrorType.ISV_MISSING_PARAMETER);
        //服务业务参数失效
        INVALIDE_CONSTRAINT_SUBERROR_MAPPINGS.put("NotEmpty", SubErrorType.ISV_INVALID_PARAMETE);
        INVALIDE_CONSTRAINT_SUBERROR_MAPPINGS.put("Size", SubErrorType.ISV_INVALID_PARAMETE);
        INVALIDE_CONSTRAINT_SUBERROR_MAPPINGS.put("Length", SubErrorType.ISV_INVALID_PARAMETE);
        INVALIDE_CONSTRAINT_SUBERROR_MAPPINGS.put("Range", SubErrorType.ISV_INVALID_PARAMETE);
        INVALIDE_CONSTRAINT_SUBERROR_MAPPINGS.put("Pattern", SubErrorType.ISV_INVALID_PARAMETE);
        INVALIDE_CONSTRAINT_SUBERROR_MAPPINGS.put("Min", SubErrorType.ISV_INVALID_PARAMETE);
        INVALIDE_CONSTRAINT_SUBERROR_MAPPINGS.put("Max", SubErrorType.ISV_INVALID_PARAMETE);
        INVALIDE_CONSTRAINT_SUBERROR_MAPPINGS.put("DecimalMin", SubErrorType.ISV_INVALID_PARAMETE);
        INVALIDE_CONSTRAINT_SUBERROR_MAPPINGS.put("DecimalMax", SubErrorType.ISV_INVALID_PARAMETE);
        INVALIDE_CONSTRAINT_SUBERROR_MAPPINGS.put("Digits", SubErrorType.ISV_INVALID_PARAMETE);
        INVALIDE_CONSTRAINT_SUBERROR_MAPPINGS.put("Past", SubErrorType.ISV_INVALID_PARAMETE);
        INVALIDE_CONSTRAINT_SUBERROR_MAPPINGS.put("Future", SubErrorType.ISV_INVALID_PARAMETE);
        INVALIDE_CONSTRAINT_SUBERROR_MAPPINGS.put("AssertFalse", SubErrorType.ISV_INVALID_PARAMETE);
    }



    /**
     * 验证系统参数
     * 1-11.检查应用平台CLIENT是否存在.
     * 1-12.检查应用类型CALL_TYPE是否存在.
     * 1-13.检查应用版本CALL_VERSION是否存在.
     * 1-14.检查请求是否超时(15分钟)
     * 2-11.检查应用appkey是否存在.
     * 2-12.检查应用appkey是否有效.
     * 3-11.检查应用method是否存在.
     * 3-12.检查应用method是否有效.
     * 4-11.检查应用version是否存在.
     * 4-12.检查应用version是否有效.
     * 5-11.检查应用session是否存在.
     * 5-12.检查应用session是否失效.
     * 6-11.检查服务方法的版本是否已经过期.
     * 7-11.检查应用HttpAction方法的匹配性.
     * 8-11.检查应用fromat格式化.
     * 9-11.检查应用bindObject参数.
     * 10-1.检查应用sign签名是否存在.
     * 10-2.检查应用sign签名是否有效.
     * @param xboxRequestContext
     * @return
     */
    @Override
    public MainError validateSystemParameters(DefaultXboxRequestContext xboxRequestContext) {
        XboxContext xboxContext = xboxRequestContext.getXboxContext();
        Locale locale = xboxRequestContext.getLocale();
        //错误信息
        MainError mainError = null;

        /**
         * 【1-11】检查应用平台CLIENT（系统错误代码：ER_042(系统错误)）
         */
        mainError = checkClient(xboxRequestContext);
        if (null != mainError){
            return mainError;
        }

        /**
         * 【1-12】检查应用类型（系统错误代码：ER_043(系统错误)）
         * 【1-12】检查应用类型（系统错误代码：ER_044(系统错误)）
         */
        mainError = checkCallType(xboxRequestContext);
        if (null != mainError){
            return mainError;
        }

        /**
         * 【1-13】检查应用版本（系统错误代码：ER_045(系统错误)）
         */
        mainError = checkCallVersion(xboxRequestContext);
        if (null != mainError){
            return mainError;
        }

        /**
         * 【1-14】检查请求是否超时(15分钟).（系统错误代码：ER_041(系统错误)）
         */
        mainError = checkRequestTimeout(xboxRequestContext);
        if (null != mainError){
            return mainError;
        }

        /**
         * 【2-11】检查应用appkey是否存在.（系统错误代码：ER_022(秘钥丢失)）
         */
        if (null == xboxRequestContext.getAppKey()) {
            return MainErrors.getMainError(MainErrorType.MISSING_APP_KEY, locale);
        }

        /**
         * 【2-12】检查应用appkey是否有效.（系统错误代码：ER_023(秘钥失效)）
         */
        if (!appSecretManager.isValidAppKey(xboxRequestContext.getAppKey())) {
            return MainErrors.getMainError(MainErrorType.INVALID_APP_KEY, locale);
        }

        /**
         * 【3-11】检查应用method是否存在.（系统错误代码：ER_026(方法丢失)）
         */
        if (null == xboxRequestContext.getMethod()) {
            return MainErrors.getMainError(MainErrorType.MISSING_METHOD, locale);
        }

        /**
         * 【3-12】检查应用method是否有效.（系统错误代码：ER_027(方法失效)）
         */
        if (!xboxContext.containsMethod(xboxRequestContext.getMethod())) {
            return MainErrors.getMainError(MainErrorType.INVALID_METHOD, locale);
        }

        /**
         * 【4-11】检查应用version是否存在.（系统错误代码：ER_028(版本丢失)）
         */
        if (null == xboxRequestContext.getVersion()) {
            return MainErrors.getMainError(MainErrorType.MISSING_VERSION, locale);
        }

        /**
         * 【4-12】检查应用version是否有效.（系统错误代码：ER_029(版本失效)）
         */
        if (!xboxContext.isValidMethod(xboxRequestContext.getMethod(), xboxRequestContext.getVersion())) {
            return MainErrors.getMainError(MainErrorType.INVALID_VERSION, locale);
        }

        /**
         * 【5-11】检查应用session是否存在.（系统错误代码：ER_020(会话丢失)）
         * 【5-12】检查应用session是否失效.（系统错误代码：ER_021(会话失效)）
         */
        mainError = checkSession(xboxRequestContext);
        if (null != mainError) {
            return mainError;
        }

        /**
         * 【6-11】检查服务方法的版本是否已经过期.（系统错误代码：ER_008(服务方法版本不可用)）
         */
        if (xboxRequestContext.getServiceMethodHandler().getServiceMethodDefinition().isObsoleted()) {
            return MainErrors.getMainError(MainErrorType.METHOD_OBSOLETED, locale);
        }

        /**
         * 【7-11】检查应用HttpAction方法的匹配性.(系统错误代码：ER_005)
         */
        mainError = validateHttpAction(xboxRequestContext);
        if (null != mainError) {
            return mainError;
        }

        /**
         * 【8-11】检查应用fromat格式化.（系统错误代码：ER_031）
         */
        if (!MessageFormat.isVaildFormat(xboxRequestContext.getFormat())) {
            return MainErrors.getMainError(MainErrorType.INVALID_FORMAT, locale);
        }

        /**
         * 【9-11】检查应用bindObject参数.（系统错误代码：ER_038）
         */
        mainError = checkBindObject(xboxRequestContext);
        if (null != mainError) {
            return mainError;
        }

        /**
         * 【10-1】检查应用sign签名是否存在.（系统错误代码：ER_024(签名丢失)）
         * 【10-2】检查应用sign签名是否有效.（系统错误代码：ER_025(签名无效)）
         */
        mainError = checkSign(xboxRequestContext);
        if (null != mainError) {
            return mainError;
        }
            return null;
    }


    /**
     * 验证其他参数
     * 1.判断应用用户(是否有权访问目标服务)
     * 2.判断应用会话(用户访问服务的次数或频度是否超限)
     * 3.如果是上传文件的服务(检查文件类型和大小是否满足要求)
     * 4.检查业务参数合法性
     * @param xboxRequestContext
     * @return
     */
    @Override
    public MainError validateOther(DefaultXboxRequestContext xboxRequestContext) {
        MainError mainError = null;
        //1.判断应用/用户 是否有权访问目标服务
        mainError = checkServcieAccess(xboxRequestContext);
        if (null != mainError) {
            return mainError;
        }
        //2.判断应用/会话/用户访问服务的次数或频度是否超限
        mainError = checkInvokeTimesLimit(xboxRequestContext);
        if (null != mainError) {
            return mainError;
        }
        //3.如果是上传文件的服务，检查文件类型和大小是否满足要求
        //4.检查业务参数合法性
        mainError = validateBusinessParams(xboxRequestContext);
        if (null != mainError) {
            return mainError;
        }
            return null;
    }


    /**
     * 检查应用平台(错误代码ER_042)
     * @param xboxRequestContext
     * @return
     */
    private MainError checkClient(DefaultXboxRequestContext xboxRequestContext){
        if(StringUtils.isEmpty(xboxRequestContext.getClient())){
            logger.info("checkClient->>检查应用平台, 返回ER_042错误码...");
            return MainErrors.getMainError(MainErrorType.MISSING_CLIENT, xboxRequestContext.getLocale());
        }
            return null;
    }

    /**
     * 检查应用类型(错误代码ER_043)
     * 检查应用类型不符合(错误代码ER_044)
     * @param xboxRequestContext
     * @return
     */
    private MainError checkCallType(DefaultXboxRequestContext xboxRequestContext){
        if(StringUtils.isEmpty(xboxRequestContext.getCallType())){
            logger.info("checkCallType->>检查应用类型, 返回ER_043错误码...");
            return MainErrors.getMainError(MainErrorType.MISSING_CALL_TYPE, xboxRequestContext.getLocale());
        }
        //验证应用类型
        if(!DeviceType.contains(xboxRequestContext.getCallType())){
            logger.info("checkCallType->>检查应用类型不符合, 返回ER_044错误码...");
            return MainErrors.getMainError(MainErrorType.INVALID_CALL_TYPE, xboxRequestContext.getLocale());
        }
            return null;
    }


    /**
     * 检查应用版本(错误代码ER_045)
     * @param xboxRequestContext
     * @return
     */
    private MainError checkCallVersion(DefaultXboxRequestContext xboxRequestContext){
        if(StringUtils.isEmpty(xboxRequestContext.getCallVersion())){
            logger.info("checkCallVersion->>检查应用版本, 返回ER_045错误码...");
            return MainErrors.getMainError(MainErrorType.MISSING_CALL_TYPE, xboxRequestContext.getLocale());
        }
        return null;
    }




    /**
     * 检查请求是否超时(默认15分钟)
     * 1.请求超时(错误代码ER_041)
     * @param xboxRequestContext
     * @return
     */
    private MainError checkRequestTimeout(DefaultXboxRequestContext xboxRequestContext){
        if (null != xboxRequestContext.getRequestTimestamp()){
            //相隔时间 = 当前系统时间  - 客户端请求时间(单位/S)
            Long diffMillisecond = System.currentTimeMillis() - xboxRequestContext.getRequestTimestamp();
            //系统失效时间15分钟(单位/S)
            Long sysLimitMillisecond = 100l * 60 * 15;
            //相隔时间 - 系统失效时间 > 0(则会话已过期)  反之(则正常)
            if (diffMillisecond - sysLimitMillisecond > 0){
                logger.info("checkRequestTimeout->>请求超时, 返回ER_041错误码...");
                return MainErrors.getMainError(MainErrorType.REQUEST_TIMEOUT, xboxRequestContext.getLocale());
            }
        }
         return null;
    }


    /**
     * 验证会话
     * 1.会话丢失(错误代码ER_020)
     * 2.会话失效(错误代码ER_021)
     * @param xboxRequestContext
     * @return
     */
    private MainError checkSession(DefaultXboxRequestContext xboxRequestContext) {
        logger.info("XboxSecurityManager-->>checkSession()-->>开始");
        //logger.info("XboxSecurityManager-->>checkSession()-->>DefaultXboxRequestContext : " + xrc);
        if (xboxRequestContext.getServiceMethodHandler() != null && xboxRequestContext.getServiceMethodHandler().getServiceMethodDefinition().isNeedInSession()) {
            //logger.info("XboxSecurityManager-->>checkSession()-->>getServiceMethodHandler() : " + xrc.getServiceMethodHandler());
            //logger.info("XboxSecurityManager-->>checkSession()-->>isNeedInSession() : " + xrc.getServiceMethodHandler().getServiceMethodDefinition().isNeedInSession());
            //logger.info("XboxSecurityManager-->>checkSession()-->>getSessionId() : " + xrc.getSessionId());
            if (StringUtils.isBlank(xboxRequestContext.getSessionId())) {
                logger.debug("checkSession->>调用方法：" + xboxRequestContext.getMethodKey() + "错误, 会话MISSING_SESSION(会话丢失)返回ER_020错误码...");
                return MainErrors.getMainError(MainErrorType.MISSING_SESSION, xboxRequestContext.getLocale());
            } else {
                if (!isValidSession(xboxRequestContext)) {
                    logger.debug("checkSession->>调用方法：" + xboxRequestContext.getMethodKey() + "错误, 会话INVALID_SESSION(会话失效)返回ER_021错误码...");
                    return MainErrors.getMainError(MainErrorType.INVALID_SESSION, xboxRequestContext.getLocale());
                }
            }
        }
        logger.info("XboxSecurityManager-->>checkSession()-->>结束");
        return null;
    }


    /**
     * 验证会话
     * @param xboxRequestContext
     * @return
     */
    private boolean isValidSession(DefaultXboxRequestContext xboxRequestContext) {
        Session session = sessionManager.getSession(xboxRequestContext.getSessionId());
        if (null == session) {
            if (logger.isDebugEnabled()) {
                logger.debug("调用方法" + xboxRequestContext.getMethodKey() + "缺少对应的SessionId");
            }
            return false;
        } else {
            return true;
        }

    }

    /**
     * 校验绑定参数对象
     * 1.绑定参数缺失(错误代码ER_038)
     * @param xboxRequestContext
     * @return
     */
    private MainError checkBindObject(DefaultXboxRequestContext xboxRequestContext) {
        if (xboxRequestContext.getServiceMethodHandler().isXboxRequestImplType() && xboxRequestContext.getBindObject() == null) {
            logger.debug("checkBindObject->>调用方法：" + xboxRequestContext.getMethodKey() + "错误, MISSING_BINDOBJECT(缺失绑定参数对象)返回ER_038错误码...");
            MainError mainError = MainErrors.getMainError(MainErrorType.MISSING_BINDOBJECT, xboxRequestContext.getLocale());
            return mainError;
        }
            return null;

    }

    /**
     * 验证HttpAction方法(错误代码ER_005)
     * 1.HttpAction不允许(不匹配)
     * @param xboxRequestContext
     * @return
     */
    private MainError validateHttpAction(DefaultXboxRequestContext xboxRequestContext) {
        HttpAction[] httpActions = xboxRequestContext.getServiceMethodHandler().getServiceMethodDefinition().getHttpActions();
        if (null != httpActions && httpActions.length > 0) {
            boolean isVaild = false;
            for (HttpAction httpAction : httpActions) {
                if (httpAction == xboxRequestContext.getHttpAction()) {
                    isVaild = true;
                }
            }
            if (!isVaild) {
                logger.debug("validateHttpAction->>调用方法：" + xboxRequestContext.getMethodKey() + "错误, HTTP_ACTION_NOT_ALLOWED(HttpAction不允许)返回ER_005错误码...");
                return MainErrors.getMainError(MainErrorType.HTTP_ACTION_NOT_ALLOWED, xboxRequestContext.getLocale());
            }
        }
        return null;
    }


    /**
     * 检查Sign签名(默认忽略签名) 已配置为true
     * 全局配置需要验证签名 且 方法也配置了需要签名(全局为默认忽略,方法默认开启)
     * 1.签名丢失(错误代码ER_024)
     * 2.签名失效(错误代码ER_025)
     * @param xboxRequestContext
     * @return
     */
    private MainError checkSign(DefaultXboxRequestContext xboxRequestContext) {
        if (xboxRequestContext.isSignEnable()) {
            if (!xboxRequestContext.getServiceMethodHandler().getServiceMethodDefinition().isIgnoreSign()) {
                logger.info("checkSign-->>校验签名-->>开始");
                String sign = xboxRequestContext.getSign();
                /**
                 * 1.签名丢失, 为空验证
                 */
                if (StringUtils.isEmpty(sign)) {
                    return MainErrors.getMainError(MainErrorType.MISSING_SIGNATURE, xboxRequestContext.getLocale());
                }

                /**
                 * 2.验证签名, (签名规则[七项基本参数(client + callType + callVersion + appKey + format + method + version)] + [业务参数(bindObject)] + [会话标识(sessionId)])
                 */
                //构建签名对象
                SignRule signRule = new SignRule();

                //获取应用callType
                String callType = xboxRequestContext.getCallType();
                //获取应用callVersion
                String callVersion = xboxRequestContext.getCallVersion();
                //获取应用client
                String client = xboxRequestContext.getClient();
                //获取应用appkey
                String appKey = xboxRequestContext.getAppKey();
                //获取应用format
                String format = xboxRequestContext.getFormat();
                //获取应用method
                String method = xboxRequestContext.getMethod();
                //获取应用version
                String version = xboxRequestContext.getVersion();
                //获取应用sessionId
                String sessionId = xboxRequestContext.getSessionId();
                //获取应用appBrand
                String appBrand = xboxRequestContext.getAppBrand();
                //获取应用appBaseInfo
                String appBaseInfo = xboxRequestContext.getAppBaseInfo();

                /**
                 * 2.业务参数验证
                 */
                //获取应用bindObject
                String bindObject = xboxRequestContext.getBindObject();
//                logger.info("checkSign-->>获取应用appkey: " + appkey);
//                logger.info("checkSign-->>获取应用bindObject: " + bindObject);
//                logger.info("checkSign-->>获取应用callType: " + callType);
//                logger.info("checkSign-->>获取应用callVersion: " + callVersion);
//                logger.info("checkSign-->>获取应用client: " + client);
//                logger.info("checkSign-->>获取应用format: " + format);
//                logger.info("checkSign-->>获取应用method: " + method);
//                logger.info("checkSign-->>获取应用sessionId: " + sessionId);
//                logger.info("checkSign-->>获取应用version: " + version);
//                logger.info("checkSign-->>获取应用appBrand: " + appBrand);
//                logger.info("checkSign-->>获取应用appBaseInfo: " + appBaseInfo);


                /**
                 * 七项基本参数验证（为空验证）
                 * 签名不通过
                 */
                if(StringUtils.isEmpty(callType) || StringUtils.isEmpty(callVersion) || StringUtils.isEmpty(client) || StringUtils.isEmpty(appKey) || StringUtils.isEmpty(format) || StringUtils.isEmpty(method) || StringUtils.isEmpty(version)){
                    return MainErrors.getMainError(MainErrorType.INVALID_SIGNATURE, xboxRequestContext.getLocale());
                }

                //设置七项业务参数， 两项基本参数
                signRule.setAppKey(appKey);
                signRule.setBindObject(bindObject.replaceAll("\r|\n|\t", ""));
                signRule.setCallType(callType);
                signRule.setCallVersion(callVersion);
                signRule.setClient(client);
                signRule.setFormat(format);
                signRule.setMethod(method);
                signRule.setSessionId(sessionId);
                signRule.setVersion(version);
                signRule.setAppBrand(appBrand);
                signRule.setAppBaseInfo(appBaseInfo);

                //获取签名报文
                String signString = JsonUtil_Google.getJsonStringByObject(signRule);
                logger.info("checkSign-->>签名报文signString :" + signString);

                //获取签名结果
                String signStr = HmacSHA1.Encrypt(signString, Constants.ZSD_COMPANY_SERVER_MESSAGE_PASSWORD);
                String signValue = Base64.encodeToString(signStr.getBytes(), 2);
                logger.info("checkSign-->>签名密码signValue : " + signValue);

                //验证签名匹配
                if (!sign.equals(signValue)) {
                    if (logger.isErrorEnabled()) {
                        logger.error("调用服务 " + xboxRequestContext.getMethodKey() + " [服务端]sign = " + signValue + " [客户端]sign = " + sign + " 【不匹配】异常");
                    }
                    return MainErrors.getMainError(MainErrorType.INVALID_SIGNATURE, xboxRequestContext.getLocale());
                }
                logger.info("checkSign-->>校验签名-->>结束");
            } 
        } else {
                if (logger.isInfoEnabled()) {
                    logger.info("服务" + xboxRequestContext.getMethodKey() + "不需要签名");
                }
        }
                return null;
    }

    /**
     * 检查业务参数
     * 1.服务不存在
     * 2.服务业务参数丢失
     * 3.服务业务参数失效
     * 4.服务业务参数不匹配
     * 5.业务参数不匹配
     * @param xboxRequestContext
     * @return
     */
    private MainError validateBusinessParams(DefaultXboxRequestContext xboxRequestContext) {
        //获取业务参数错误集
        List<ObjectError> errors = (List<ObjectError>) xboxRequestContext.getAttribute(DefaultXboxRequestContext.SPRING_VALIDATE_ERROR_ATTRNAME);
        if (null != errors && errors.size() > 0) {
            //服务不存在
            if(hasSubErrorType(errors, SubErrorType.ISV_NOT_EXIST)){
                return getBusinessParameterMainError(errors, xboxRequestContext.getLocale(), SubErrorType.ISV_NOT_EXIST);
            }
            //服务业务参数丢失
            else if(hasSubErrorType(errors, SubErrorType.ISV_MISSING_PARAMETER)){
                return getBusinessParameterMainError(errors, xboxRequestContext.getLocale(), SubErrorType.ISV_MISSING_PARAMETER);
            }
            //服务业务参数失效
            else if(hasSubErrorType(errors, SubErrorType.ISV_INVALID_PARAMETE)){
                return getBusinessParameterMainError(errors, xboxRequestContext.getLocale(), SubErrorType.ISV_INVALID_PARAMETE);
            }
            //服务业务参数不匹配
            else if(hasSubErrorType(errors, SubErrorType.ISV_INVALID_PERMISSION)){
                return getBusinessParameterMainError(errors, xboxRequestContext.getLocale(), SubErrorType.ISV_INVALID_PERMISSION);
            }
            //业务参数不匹配
            else{
                return getBusinessParameterMainError(errors, xboxRequestContext.getLocale(), SubErrorType.ISV_PARAMETERS_MISMATCH);
            }
        } else {
            return null;
        }
    }

    private MainError getBusinessParameterMainError(List<ObjectError> errors, Locale locale, SubErrorType subErrorType) {
        MainError mainError = SubErrors.getMainError(subErrorType, locale);
        for (ObjectError objectError : errors) {
            if (objectError instanceof FieldError) {
                FieldError fieldError = (FieldError) objectError;
                SubErrorType tempSubErrorType = INVALIDE_CONSTRAINT_SUBERROR_MAPPINGS.get(fieldError.getCode());
                if (subErrorType == tempSubErrorType) {
                    String subErrorCode = SubErrors.getSubErrorCode(tempSubErrorType, fieldError.getField(), fieldError.getRejectedValue());
                    SubError subError = SubErrors.getSubError(subErrorCode, tempSubErrorType.value(), locale, fieldError.getField(), fieldError.getRejectedValue(), fieldError.getDefaultMessage());
                    mainError.addSubError(subError);
                }
            }
        }
        return mainError;
    }


    /**
     *
     * @param errors
     * @param locale
     * @return
     */
    private MainError createMainErrorFromSpringValidateError(List<ObjectError> errors, Locale locale) {
        if (hasSubErrorType(errors, SubErrorType.ISV_MISSING_PARAMETER)) {
            return getBusinessParameterMainError(errors, locale, SubErrorType.ISV_MISSING_PARAMETER);
        } else if (hasSubErrorType(errors, SubErrorType.ISV_INVALID_PARAMETE)) {
            return getBusinessParameterMainError(errors, locale, SubErrorType.ISV_INVALID_PARAMETE);
        } else {/*if(hasSubErrorType(errors,SubErrorType.ISV_PARAMETERS_MISMATCH))*/
            return getBusinessParameterMainError(errors, locale, SubErrorType.ISV_PARAMETERS_MISMATCH);
        }
    }




    private boolean hasSubErrorType(List<ObjectError> errors, SubErrorType subErrorType) {
        for (ObjectError objectError : errors) {
            if (objectError instanceof FieldError) {
                FieldError fieldError = (FieldError) objectError;
                if (INVALIDE_CONSTRAINT_SUBERROR_MAPPINGS.containsKey(fieldError.getCode())) {
                    SubErrorType tempSubErrorType = INVALIDE_CONSTRAINT_SUBERROR_MAPPINGS.get(fieldError.getCode());
                    if (subErrorType == tempSubErrorType) {
                        return true;
                    }
                }
            }
        }
        return false;
    }


    private MainError checkInvokeTimesLimit(DefaultXboxRequestContext xboxRequestContext) {

        //超过方法调用频率次数
        if (invokeTimesController.isMethodInvokeFrequencyExceed(xboxRequestContext)) {
            return MainErrors.getMainError(MainErrorType.EXCEED_METHOD_INVOKE_FREQUENCY_LIMITED, xboxRequestContext.getLocale());
        }

        //超过方法调用次数
        if (invokeTimesController.isMethodInvokeLimitExceed(xboxRequestContext)) {
            return MainErrors.getMainError(MainErrorType.EXCEED_METHOD_INVOKE_LIMITED, xboxRequestContext.getLocale());
        }


        //超过应用次数
        if (invokeTimesController.isAppInvokeLimitExceed(xboxRequestContext)) {
            return MainErrors.getMainError(MainErrorType.EXCEED_APP_INVOKE_LIMITED, xboxRequestContext.getLocale());
        }

        //超过应用调用频率次数
        if (invokeTimesController.isAppInvokeFrequencyExceed(xboxRequestContext)) {
            return MainErrors.getMainError(MainErrorType.EXCEED_APP_INVOKE_FREQUENCY_LIMITED, xboxRequestContext.getLocale());
        }

        //超过会话访问次数
        if (invokeTimesController.isSessionInvokeLimitExceed(xboxRequestContext)) {
            return MainErrors.getMainError(MainErrorType.EXCEED_SESSION_INVOKE_LIMITED, xboxRequestContext.getLocale());
        }

        //超过用户调用次数
        if (invokeTimesController.isUserInvokeLimitExceed(xboxRequestContext)) {
            return MainErrors.getMainError(MainErrorType.EXCEED_USER_INVOKE_LIMITED, xboxRequestContext.getLocale());
        } else {
            return null;
        }
    }



    private MainError checkServcieAccess(DefaultXboxRequestContext xboxRequestContext) {
        if (!serviceAccessController.isAppGranted(xboxRequestContext.getAppKey(), xboxRequestContext.getMethod(), xboxRequestContext.getVersion())) {
            MainError mainError = SubErrors.getMainError(SubErrorType.ISV_INVALID_PERMISSION, xboxRequestContext.getLocale());
            SubError subError = SubErrors.getSubError(SubErrorType.ISV_INVALID_PERMISSION.value(), SubErrorType.ISV_INVALID_PERMISSION.value(),xboxRequestContext.getLocale());
            if(null != mainError && null != subError){
                mainError.addSubError(subError);
            }
            if (mainError != null && logger.isInfoEnabled()) {
                logger.info("未向" + xboxRequestContext.getAppKey() + "开放 " + ServiceMethodDefinition.methodWithVerion(xboxRequestContext.getMethod(), xboxRequestContext.getVersion()));
            }
            return mainError;
        } else {
            if (!serviceAccessController.isUserGranted(xboxRequestContext.getSession(), xboxRequestContext.getMethod(), xboxRequestContext.getVersion())) {
                MainError mainError = MainErrors.getMainError(MainErrorType.INSUFFICIENT_USER_PERMISSIONS, xboxRequestContext.getLocale());
                SubError subError = SubErrors.getSubError(SubErrorType.ISV_INVALID_PERMISSION.value(), SubErrorType.ISV_INVALID_PERMISSION.value(),xboxRequestContext.getLocale());
                if(null != mainError && null != subError){
                    mainError.addSubError(subError);
                }
                if (mainError != null && logger.isInfoEnabled()) {
                    logger.info("未向会话用户开放该服务的执行权限: " + ServiceMethodDefinition.methodWithVerion(xboxRequestContext.getMethod(), xboxRequestContext.getVersion()));
                }
                return mainError;
            }
        }
        return null;
    }

    @Override
    public void setInvokeTimesController(InvokeTimesController invokeTimesController) {
        this.invokeTimesController = invokeTimesController;
    }

    @Override
    public void setServiceAccessController(ServiceAccessController serviceAccessController) {
        this.serviceAccessController = serviceAccessController;
    }

    @Override
    public void setAppSecretManager(AppSecretManager appSecretManager) {
        this.appSecretManager = appSecretManager;
    }

    @Override
    public ServiceAccessController getServiceAccessController() {
        return serviceAccessController;
    }

    @Override
    public InvokeTimesController getInvokeTimesController() {
        return invokeTimesController;
    }

    @Override
    public AppSecretManager getAppSecretManager() {
        return appSecretManager;
    }

    @Override
    public SessionManager getSessionManager() {
        return sessionManager;
    }

    public void setSessionManager(SessionManager sessionManager) {
        this.sessionManager = sessionManager;
    }
}
